/*
 * cpu-x86.h - header for X86 hardware features
 */

static inline void native_write_msr(unsigned int msr,
                                    unsigned low, unsigned high)
{
        asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory");
}

typedef uint64_t u64;

#define DECLARE_ARGS(val, low, high)    unsigned low, high
#define EAX_EDX_VAL(val, low, high)     ((low) | ((u64)(high) << 32))
#define EAX_EDX_ARGS(val, low, high)    "a" (low), "d" (high)
#define EAX_EDX_RET(val, low, high)     "=a" (low), "=d" (high)

static inline unsigned long long native_read_msr(unsigned int msr)
{
        DECLARE_ARGS(val, low, high);

        asm volatile("rdmsr" : EAX_EDX_RET(val, low, high) : "c" (msr));
        return EAX_EDX_VAL(val, low, high);
}

#define wrmsrl(msr, val)                                        \
        native_write_msr((msr), (uint32_t)((uint64_t)(val)),    \
             (uint32_t)((uint64_t)(val) >> 32))

#define rdmsrl(msr, val)                        \
        ((val) = native_read_msr((msr)))

#define MSR_FS_BASE     0xc0000100
#define MSR_GS_BASE     0xc0000101
#define MSR_KERNEL_GS_BASE  0xc0000102
#define MSR_LSTAR       0xc0000082 /* long mode SYSCALL target */

struct tptr {
    uint16_t    limit;
    uint64_t    base;
} __attribute__((packed));

#define IDTD_P                  (1 << 7)
#define IDTD_CPL3       (3 << 5)
#define IDTD_TRAP_GATE          0xF
#define IDTD_INTERRUPT_GATE     0xE

#define IDT_ENTRIES     256

struct idtd {
        uint16_t        low;
        uint16_t        selector;
        uint8_t         ist;
        uint8_t         type;
        uint16_t        middle;
        uint32_t        high;
        uint32_t        zero;
} __attribute__((packed)) __attribute__ ((aligned));

/* x86 trap codes */
#define T_DIVIDE     0      // divide error
#define T_DEBUG      1      // debug exception
#define T_NMI        2      // non-maskable interrupt
#define T_BRKPT      3      // breakpoint
#define T_OFLOW      4      // overflow
#define T_BOUND      5      // bounds check
#define T_ILLOP      6      // illegal opcode
#define T_DEVICE     7      // device not available
#define T_DBLFLT     8      // double fault
/* #define T_COPROC  9 */   // reserved (not generated by recent processors)
#define T_TSS       10      // invalid task switch segment
#define T_SEGNP     11      // segment not present
#define T_STACK     12      // stack exception
#define T_GPFLT     13      // genernal protection fault
#define T_PGFLT     14      // page fault
/* #define T_RES    15 */   // reserved
#define T_FPERR     16      // floating point error
#define T_ALIGN     17      // aligment check
#define T_MCHK      18      // machine check
#define T_SIMDERR   19      // SIMD floating point error

// These are arbitrarily chosen, but with care not to overlap
// processor defined exceptions or interrupt vectors.
#define T_SYSCALL   48      // system call
